package com.ltw.dreamer.common.schedule;

import java.util.Calendar;
import java.util.List;
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.ltw.dreamer.common.network.WebPageReader;
import com.ltw.dreamer.stock.mapper.StockMapper;
import com.ltw.dreamer.stock.model.Stock;
import com.ltw.dreamer.stock.model.StockExample;
import com.ltw.dreamer.stock.model.StockExample.Criteria;
import com.ltw.dreamer.stock.util.StockUtil;
@Component
public class StockTask {
	@Resource
	private StockMapper stockMapper = null;
	
	@Resource
	private WebPageReader reader = null;
	
	private Logger logger = Logger.getLogger(StockTask.class);
	
	@Scheduled(cron="0 0 0 * * ?")
	@Transactional
	public void updateStock() {
		String content = reader.read("http://quote.eastmoney.com/stocklist.html");
		Document doc = Jsoup.parse(content);
		if (doc == null) {
			logger.info("读取股票代码列表文件失败。");
			return ;
		}
		updateStock(doc);
	}
	
	private void updateStock(Document doc) {
		Elements elements = doc.getElementsByClass("quotebody");
		if (elements == null) {
			logger.info("股票代码信息有变化，未能找到class=quotebody的元素");
			return ;
		}
		
		if (elements.size() > 1)
			logger.info("股票代码信息有变化，查询class=quotebody的元素时返回多条，只处理第一条数据");
		
		Element rootElement = elements.get(0);
		updateStock(rootElement);
	}

	private void updateStock(Element rootElement) {
		String market = "";
		for (Element element : rootElement.getAllElements()) {
			if (isMarketElement(element)) market = element.text();
			
			if (isStockElement(element)) updateStock(element, market);
		}
	}
	
	private boolean isMarketElement(Element element) {
		if (element == null) return false;
		return "div".equalsIgnoreCase(element.tagName()) && element.hasClass("sltit");
	}
	
	private boolean isStockElement(Element element) {
		if (element == null) return false;
		return "li".equalsIgnoreCase(element.tagName());
	}
	
	private void updateStock(Element element, String market) {
		String data = element.text();
		if (data == null) return ;
		
		StockUtil.compile(data);
		String stockName = StockUtil.getStockName();
		String stockCode = StockUtil.getStockCode();
		
		if (stockName == null || stockCode == null) return ;
		
		Stock stock = new Stock();
		stock.setCode(stockCode);
		stock.setName(stockName);
		stock.setMarket(market);
		
		if (nochange(stock)) return;
		if (shouldUpdate(stock)) {
			update(stock);
			return ;
		}
		insert(stock);
	}

	private boolean nochange(Stock stock) {
		StockExample example = new StockExample();
		Criteria criteria = example.createCriteria();
		criteria.andCodeEqualTo(stock.getCode());
		criteria.andNameEqualTo(stock.getName());
		criteria.andMarketEqualTo(stock.getMarket());
		
		List<Stock> result = stockMapper.selectByExample(example);
		return (result != null && result.size() != 0);
	}
	
	private boolean shouldUpdate(Stock stock) {
		Stock dbStock = stockMapper.selectByPrimaryKey(stock.getCode());
		return (dbStock != null);
	}
	
	private void update(Stock stock) {
		String marketCode = getMarketCode(stock.getMarket());
		stock.setMarketCode(marketCode);
		stock.setUpdatedDate(Calendar.getInstance().getTime());
		stockMapper.updateByPrimaryKey(stock);
	}

	private void insert(Stock stock) {
		String marketCode = getMarketCode(stock.getMarket());
		stock.setMarketCode(marketCode);
		
		stock.setCreatedDate(Calendar.getInstance().getTime());
		stock.setUpdatedDate(Calendar.getInstance().getTime());
		stockMapper.insert(stock);
	}
	
	
	private String getMarketCode(String market) {
		if (market == null) return "";
		market = market.trim();
		if (market.equals("上海股票")) return "sh";
		if (market.equals("深圳股票")) return "sz";
		return "";
	}
}
